#include "stdafx.h"
#include "ServerThreads.h"
#include "../Common/CommonNetwork.h"
#include "Server.h"
#include "../Common/Commonwinsock.h"


DWORD WINAPI ListenThread(LPVOID arg)
{
	listen_thread_arg* Arg = (listen_thread_arg*)arg;

	assert(Arg->PtrServer != NULL);
	
	network ServiceListen, BroadcastListen;
	if(ServiceListen.Initialize(NC_TCP_LISTENING, std::string(), Arg->ServicePort) == false) {
		Arg->PtrServer->CriticalError(winsock::GetErrorCode());
		return -1;
	}

	if(BroadcastListen.Initialize(NC_TCP_LISTENING, std::string(), Arg->BroadcastPort) == false) {
		Arg->PtrServer->CriticalError(winsock::GetErrorCode());
		return -1;
	}
	
	BOOL optval = TRUE;
	while(1)
	{
		network* Service = new network;	
		network* Broadcast = new network;

		if((Service->Initialize(&ServiceListen) == false) || 
			(Broadcast->Initialize(&BroadcastListen) == false ) ) {
				Arg->PtrServer->NormalError(winsock::GetErrorCode());
				delete Service;
				delete Broadcast;
				continue;
		}		

		Service->Attribute(IPPROTO_TCP, TCP_NODELAY, (char *) &optval, sizeof(optval));
		Broadcast->Attribute(IPPROTO_TCP, TCP_NODELAY, (char *) &optval, sizeof(optval));

		if(Arg->PtrServer->NewClient(Service,Broadcast) == false ) {
			Arg->PtrServer->DisplayText(_T("New Client Accept. But Server is full."));
			delete Service;
			delete Broadcast;			
			continue;
		}			
	}

	return NULL;
}



DWORD WINAPI ServiceThread(LPVOID arg) {	
	service_thread_arg* ServiceThreadArg = (service_thread_arg*)arg;
	
	assert(ServiceThreadArg->PtrServer != NULL);
	assert(ServiceThreadArg->PtrClientManager != NULL);
	assert(ServiceThreadArg->PtrServiceNetwork != NULL);

	bool Result;

	while(1) {
		SERVICE_MESSAGE ServiceMessage;
		int RealLen = 0;
		Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ServiceMessage, sizeof(SERVICE_MESSAGE), &RealLen);
		if(Result == false)
			break;

		assert(sizeof(SERVICE_MESSAGE) == RealLen);

		switch(ServiceMessage) {
			case S_REQUEST_CODE: {
					service_msg_REQUEST_CODE ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_REQUEST_CODE), &RealLen);
					assert(sizeof(service_msg_REQUEST_CODE) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_REQUEST_CLIENT: {
					service_msg_REQUEST_CLIENT ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_REQUEST_CLIENT), &RealLen);
					assert(sizeof(service_msg_REQUEST_CLIENT) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_REQUEST_OBJECT: {
					service_msg_REQUEST_OBJECT ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_REQUEST_OBJECT), &RealLen);
					assert(sizeof(service_msg_REQUEST_OBJECT) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_REQUEST_RELAY_LINK: {
					service_msg_REQUEST_RELAY_LINK ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_REQUEST_OBJECT), &RealLen);
					assert(sizeof(service_msg_REQUEST_OBJECT) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_NOTICE_NEW_OBJECT: {
					service_msg_NOTICE_NEW_OBJECT ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_NOTICE_NEW_OBJECT), &RealLen);
					assert(sizeof(service_msg_NOTICE_NEW_OBJECT) == RealLen);
					// recv extra data. 
					ReceiveData.ExtraPtr = new char[ReceiveData.ExtraLength];
					Result = ServiceThreadArg->PtrServiceNetwork->Recv(ReceiveData.ExtraPtr, ReceiveData.ExtraLength, &RealLen);
					assert(ReceiveData.ExtraLength == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);

					delete [] ReceiveData.ExtraPtr;
				}
				break;

			case S_NOTICE_DEL_OBJECT: {
					service_msg_NOTICE_DEL_OBJECT ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_NOTICE_DEL_OBJECT), &RealLen);
					assert(sizeof(service_msg_NOTICE_DEL_OBJECT) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_NOTICE_MISSILE_CRUSH: {
					service_msg_NOTICE_MISSILE_CRUSH ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_NOTICE_MISSILE_CRUSH), &RealLen);
					assert(sizeof(service_msg_NOTICE_MISSILE_CRUSH) == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_NOTICE_ACCESS_OFF: {
					service_msg_NOTICE_ACCESS_OFF ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_NOTICE_ACCESS_OFF), &RealLen);
					assert(sizeof(service_msg_NOTICE_ACCESS_OFF) == RealLen); 

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;

			case S_NOTICE_MESSAGE: {
					service_msg_NOTICE_MESSAGE ReceiveData;

					Result = ServiceThreadArg->PtrServiceNetwork->Recv((char*)&ReceiveData, sizeof(service_msg_NOTICE_MESSAGE), &RealLen);
					assert(sizeof(service_msg_NOTICE_MESSAGE) == RealLen);
					
					// recv extra data.
					ReceiveData.MsgString = new char[ReceiveData.MsgLength];
					Result = ServiceThreadArg->PtrServiceNetwork->Recv(ReceiveData.MsgString, ReceiveData.MsgLength, &RealLen);
					assert(ReceiveData.MsgLength == RealLen);

					ServiceThreadArg->PtrServicer->Service(ServiceThreadArg->PtrServiceNetwork,	&ReceiveData);
				}
				break;
		}
	}	

	ServiceThreadArg->PtrServer->DeleteClient(ServiceThreadArg->PtrServiceNetwork);	

	delete ServiceThreadArg;	

	return NULL;
}



DWORD WINAPI BroadcastThread(LPVOID arg) {

	broadcast_thread_arg* BroadcastThreadArg = (broadcast_thread_arg*)arg;

	assert(BroadcastThreadArg->PtrBroadcaster != NULL);

	while(1) 
		BroadcastThreadArg->PtrBroadcaster->Send(); 		
	
	delete BroadcastThreadArg;

	return NULL;
}



DWORD WINAPI AccessKeeperThread(LPVOID arg) 
{
	access_keeper_thread_arg* AccessKeeperThreadArg = (access_keeper_thread_arg*) arg;

	assert(AccessKeeperThreadArg->PtrBroadcaster != NULL);

	while(1)
	{
		AccessKeeperThreadArg->PtrBroadcaster->PushMessageCheckSocket();
		Sleep(10000);
	}
	return NULL;
}



DWORD WINAPI ObjectRelayThread(LPVOID arg) {
	object_relay_thread_arg* ObjectRelayThreadArg = (object_relay_thread_arg*)arg;	

	assert(ObjectRelayThreadArg->PtrClientManager != NULL);
	assert(ObjectRelayThreadArg->PtrServerUdpNetwork != NULL);

	bool Result;

	SYNC_TYPE GetType;
	int RecvLen;

	char	Buffer[MAX_SYNC_LENGTH];
	ip		RecvIP;
	port	RecvPort;

	while(1) {
		Result = ObjectRelayThreadArg->PtrServerUdpNetwork->RecvUDP(Buffer, MAX_SYNC_LENGTH, 
												&RecvLen, &RecvIP, &RecvPort);
		if(Result == false) 
			continue;
		
		if(RecvLen == sizeof(sync_object_3d)) {	// recv object data. 
			// resend object data to all clients .
			ObjectRelayThreadArg->PtrServerUdpNetwork->SendGroup(Buffer, sizeof(sync_object_3d));			

#ifdef _DEBUG // debug info. print recv count. 
			ObjectRelayThreadArg->PtrClientManager->Lock();
			client_manager::client_save_structure* pClientInfo = NULL;
			pClientInfo = ObjectRelayThreadArg->PtrClientManager->SearchClient(((sync_object_3d*)Buffer)->OwnerCode);
			if(pClientInfo != NULL) {
				if(pClientInfo->LastUdpRecvCountUpdate + 1000 < GetTickCount()) {
					pClientInfo->LastUdpRecvCountUpdate = GetTickCount();
					pClientInfo->LastUdpRecvCount = pClientInfo->CurrentUdpRecvCount;
					pClientInfo->CurrentUdpRecvCount = 0;
				}
				pClientInfo->CurrentUdpRecvCount++;
			}
			ObjectRelayThreadArg->PtrClientManager->UnLock();
#endif
		}

		else if(RecvLen == sizeof(sync_link)) { // udp link data. 
			sync_link* SyncLinkData = (sync_link*)Buffer;

			ObjectRelayThreadArg->PtrClientManager->Lock();
			client_manager::client_save_structure* pClientInfo = NULL;
			pClientInfo = ObjectRelayThreadArg->PtrClientManager->SearchClient(SyncLinkData->ClienetCode);
			assert(pClientInfo != NULL);
			if(pClientInfo != NULL) 
				if(pClientInfo->UdpPort == UDP_NOT_READY) { // net yet link udp.					
						if(BORDER_COUNTER < ++(pClientInfo->UdpConnectCount)) {
							// add safe code. 
							pClientInfo->UdpPort = ntohs(RecvPort);	
							ObjectRelayThreadArg->PtrServerUdpNetwork->AddMulticastGroup(RecvIP, RecvPort);						
						}
				}

#ifdef _DEBUG   // debug info. print udp data count. 
				pClientInfo->UdpConnectCount++;
#endif
			ObjectRelayThreadArg->PtrClientManager->UnLock();
		}		
	}
	
	delete ObjectRelayThreadArg;
	
	return NULL;
}